package com.hb.common.utils.sql;

import cn.hutool.core.exceptions.UtilException;
import cn.hutool.extra.spring.SpringUtil;
import com.google.common.collect.Lists;

import com.hb.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.Arrays;
import java.util.List;
import java.util.function.BiConsumer;

/**
 * sql操作工具类
 *
 * @author hb
 */

@Slf4j
public class SqlUtil
{
    /**
     * 仅支持字母、数字、下划线、空格、逗号、小数点（支持多个字段排序）
     */
    public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";

    /**
     * 检查字符，防止注入绕过
     */
    public static String escapeOrderBySql(String value)
    {
        if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
        {
            throw new UtilException("参数不符合规范，不能进行查询");
        }
        return value;
    }

    /**
     * 验证 order by 语法是否符合规范
     */
    public static boolean isValidOrderBySql(String value)
    {
        return value.matches(SQL_PATTERN);
    }

    /**
     * 批量新增方法
     *
     * @param list       要新增的集合
     * @param clazz      Mapper类
     * @param biConsumer 对应的单条新增方法
     * @param <M>        mapper类型
     * @param <T>        结合元素类型
     */
    public static  <M, T> void batchInsert(List<T> list, Class<M> clazz, BiConsumer<M, T> biConsumer) {
        if (list == null || list.size() == 0) {
            log.info("BatchInsertUtil batchInsert list data is null!");
            return;
        }
        SqlSessionFactory sqlSessionFactory = SpringUtil.getBean(SqlSessionFactory.class);
        SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
        try {
            M mapper = session.getMapper(clazz);
            list.forEach(a -> {
                biConsumer.accept(mapper, a);
            });
            session.commit();
            session.clearCache();
        } catch (Exception e) {
            log.error("BatchInsertUtil batchInsert is exception！clazz={}", clazz.getName(), e);
            session.rollback();
            throw e;
        } finally {
            session.close();
        }
    }

    public static <M, T> void batchInsertBySpeed(List<T> list, Class<M> clazz, BiConsumer<M, T> biConsumer, int size) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        SqlSessionFactory sqlSessionFactory = SpringUtil.getBean(SqlSessionFactory.class);
        SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
        try {
            M mapper = session.getMapper(clazz);
            List<List<T>> partition = list.size() > size ? Lists.partition(list, size) : Arrays.asList(list);
            partition.forEach(v -> {
                v.forEach(a -> biConsumer.accept(mapper, a));
                session.commit();
                session.clearCache();
            });
        } catch (Exception e) {
            session.rollback();
            throw e;
        } finally {
            session.close();
        }
    }


}
